﻿Imports System.Threading
Imports System.Threading.Tasks
Imports System.Collections.Concurrent

Public Class VM_Stats

	Public Class ReportTotals
		Property Count As Integer

		Property threeMonthBooks As Integer
		Property threeMonthBrochures As Integer
		Property threeMonthHours As Single
		Property threeMonthMagazines As Integer
		Property threeMonthReturnVisits As Integer
		Property threeMonthBibleStudies As Integer

		Property sixMonthBooks As Integer
		Property sixMonthBrochures As Integer
		Property sixMonthHours As Single
		Property sixMonthMagazines As Integer
		Property sixMonthReturnVisits As Integer
		Property sixMonthBibleStudies As Integer

		Property twelveMonthBooks As Integer
		Property twelveMonthBrochures As Integer
		Property twelveMonthHours As Single
		Property twelveMonthMagazines As Integer
		Property twelveMonthReturnVisits As Integer
		Property twelveMonthBibleStudies As Integer

		ReadOnly Property threeMonthBooksAverage As Single
			Get
				Return threeMonthBooks / (3 * Count)
			End Get
		End Property

		ReadOnly Property threeMonthBrochuresAverage As Single
			Get
				Return threeMonthBrochures / (3 * Count)
			End Get
		End Property

		ReadOnly Property threeMonthHoursAverage As Single
			Get
				Return threeMonthHours / (3 * Count)
			End Get
		End Property

		ReadOnly Property threeMonthMagazinesAverage As Single
			Get
				Return threeMonthMagazines / (3 * Count)
			End Get
		End Property

		ReadOnly Property threeMonthReturnVisitsAverage As Single
			Get
				Return threeMonthReturnVisits / (3 * Count)
			End Get
		End Property

		ReadOnly Property threeMonthBibleStudiesAverage As Single
			Get
				Return threeMonthBibleStudies / (3 * Count)
			End Get
		End Property


		ReadOnly Property sixMonthBooksAverage As Single
			Get
				Return sixMonthBooks / (6 * Count)
			End Get
		End Property

		ReadOnly Property sixMonthBrochuresAverage As Single
			Get
				Return sixMonthBrochures / (6 * Count)
			End Get
		End Property

		ReadOnly Property sixMonthHoursAverage As Single
			Get
				Return sixMonthHours / (6 * Count)
			End Get
		End Property

		ReadOnly Property sixMonthMagazinesAverage As Single
			Get
				Return sixMonthMagazines / (6 * Count)
			End Get
		End Property

		ReadOnly Property sixMonthReturnVisitsAverage As Single
			Get
				Return sixMonthReturnVisits / (6 * Count)
			End Get
		End Property

		ReadOnly Property sixMonthBibleStudiesAverage As Single
			Get
				Return sixMonthBibleStudies / (6 * Count)
			End Get
		End Property


		ReadOnly Property twelveMonthBooksAverage As Single
			Get
				Return twelveMonthBooks / (12 * Count)
			End Get
		End Property

		ReadOnly Property twelveMonthBrochuresAverage As Single
			Get
				Return twelveMonthBrochures / (12 * Count)
			End Get
		End Property

		ReadOnly Property twelveMonthHoursAverage As Single
			Get
				Return twelveMonthHours / (12 * Count)
			End Get
		End Property

		ReadOnly Property twelveMonthMagazinesAverage As Single
			Get
				Return twelveMonthMagazines / (12 * Count)
			End Get
		End Property

		ReadOnly Property twelveMonthReturnVisitsAverage As Single
			Get
				Return twelveMonthReturnVisits / (12 * Count)
			End Get
		End Property

		ReadOnly Property twelveMonthBibleStudiesAverage As Single
			Get
				Return twelveMonthBibleStudies / (12 * Count)
			End Get
		End Property

	End Class

	Public Shared lastTwelveMonths As Date() = Enumerable.Range(1, 13).Select(Function(x) Now.AddMonths(-x).FirstOfTheMonth).OrderByDescending(Function(x) x).ToArray
	Public Shared lastSixMonths As Date() = Enumerable.Range(1, 7).Select(Function(x) Now.AddMonths(-x).FirstOfTheMonth).OrderByDescending(Function(x) x).ToArray
	Public Shared lastThreeMonths As Date() = Enumerable.Range(1, 4).Select(Function(x) Now.AddMonths(-x).FirstOfTheMonth).OrderByDescending(Function(x) x).ToArray

	Private Shared _ElderTotals As ReportTotals
	Public Shared Function ElderTotals() As ReportTotals
		If _ElderTotals Is Nothing Then
			_ElderTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.IsElder).ToList)
		End If

		Return _ElderTotals
	End Function

	Private Shared _MinisterialServantTotals As ReportTotals
	Public Shared Function MinisterialServantTotals() As ReportTotals
		If _MinisterialServantTotals Is Nothing Then
			_MinisterialServantTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.IsMinisterialServant).ToList)
		End If

		Return _MinisterialServantTotals
	End Function

	Private Shared _PioneerTotals As ReportTotals
	Public Shared Function PioneerTotals() As ReportTotals
		If _PioneerTotals Is Nothing Then
			_PioneerTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.IsPioneer).ToList)
		End If

		Return _PioneerTotals
	End Function

	Private Shared _RegAuxPioneerTotals As ReportTotals
	Public Shared Function RegAuxPioneerTotals() As ReportTotals
		If _RegAuxPioneerTotals Is Nothing Then
			_RegAuxPioneerTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.IsRegAuxPioneer).ToList)
		End If

		Return _RegAuxPioneerTotals
	End Function

	Private Shared _PublisherTotals As ReportTotals
	Public Shared Function PublisherTotals() As ReportTotals
		If _PublisherTotals Is Nothing Then
			_PublisherTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.DateImmersed IsNot Nothing AndAlso Not x.IsPioneer AndAlso Not x.IsRegAuxPioneer).ToList)
		End If

		Return _PublisherTotals
	End Function

	Private Shared _UnbaptizedPublisherTotals As ReportTotals
	Public Shared Function UnbaptizedPublisherTotals() As ReportTotals
		If _UnbaptizedPublisherTotals Is Nothing Then
			_UnbaptizedPublisherTotals = GenerateTotals(PublisherData.ActivePublishers.Where(Function(x) x.DateImmersed Is Nothing).ToList)
		End If

		Return _UnbaptizedPublisherTotals
	End Function

	Private Shared _CongregationTotals As ReportTotals
	Public Shared Function CongregationTotals() As ReportTotals
		If _CongregationTotals Is Nothing Then
			_CongregationTotals = GenerateTotals(PublisherData.ActivePublishers.ToList)
		End If

		Return _CongregationTotals
	End Function

	Public Shared Function ServiceGroupTotals() As KeyValuePair(Of String, ReportTotals)()
		Dim returnList As New List(Of KeyValuePair(Of String, ReportTotals))
		Using db As New CongregationDataContainerLocal
			For Each myGroup In db.Groups
				Dim newGroup As New KeyValuePair(Of String, ReportTotals)(myGroup.GroupName, GenerateTotals(myGroup.PublisherDatas.ToList))
				returnList.Add(newGroup)
			Next
		End Using

		Return returnList.ToArray
	End Function

	Private Shared lockObject As New Object
	Private Shared publisherCardCache As New ConcurrentDictionary(Of Long, VM_PublisherCard)
	Private Shared Function GenerateTotals(PublishersToTotal As List(Of PublisherData)) As ReportTotals

		PublishersToTotal.AsParallel.ForAll(Sub(myPublisher)
												If Not publisherCardCache.ContainsKey(myPublisher.PublisherID) Then
													publisherCardCache.GetOrAdd(myPublisher.PublisherID, New VM_PublisherCard(myPublisher.PublisherID))
												End If
											End Sub)

		Dim returnReportTotals As New ReportTotals

		Dim allReportTotals As New ConcurrentBag(Of ReportTotals)
		Dim result As ParallelLoopResult = Parallel.ForEach(Of PublisherData, ReportTotals)(PublishersToTotal.ToArray, Function()
																														   Return New ReportTotals
																													   End Function,
		  Function(myPublisher As PublisherData, loopState As ParallelLoopState, myReportTotals As ReportTotals) As ReportTotals
			  With myReportTotals

				  .Count += 1

				  Dim publisherDatum As VM_PublisherCard = publisherCardCache(myPublisher.PublisherID)

				  Dim workingThreeMonthRecords = publisherDatum.AllPublisherRecords.Where(Function(x) lastThreeMonths.Contains(x.ReportMonth))

				  .threeMonthBooks += workingThreeMonthRecords.Sum(Function(x) x.Books)
				  .threeMonthBrochures += workingThreeMonthRecords.Sum(Function(x) x.Brochures)
				  .threeMonthHours += workingThreeMonthRecords.Sum(Function(x) x.Hours)
				  .threeMonthMagazines += workingThreeMonthRecords.Sum(Function(x) x.Magazines)
				  .threeMonthReturnVisits += workingThreeMonthRecords.Sum(Function(x) x.ReturnVisits)
				  .threeMonthBibleStudies += workingThreeMonthRecords.Sum(Function(x) x.BibleStudies)

				  Dim workingSixMonthRecords = publisherDatum.AllPublisherRecords.Where(Function(x) lastSixMonths.Contains(x.ReportMonth))

				  .sixMonthBooks += workingSixMonthRecords.Sum(Function(x) x.Books)
				  .sixMonthBrochures += workingSixMonthRecords.Sum(Function(x) x.Brochures)
				  .sixMonthHours += workingSixMonthRecords.Sum(Function(x) x.Hours)
				  .sixMonthMagazines += workingSixMonthRecords.Sum(Function(x) x.Magazines)
				  .sixMonthReturnVisits += workingSixMonthRecords.Sum(Function(x) x.ReturnVisits)
				  .sixMonthBibleStudies += workingSixMonthRecords.Sum(Function(x) x.BibleStudies)

				  Dim workingTwelveMonthRecords = publisherDatum.AllPublisherRecords.Where(Function(x) lastTwelveMonths.Contains(x.ReportMonth))

				  .twelveMonthBooks += workingTwelveMonthRecords.Sum(Function(x) x.Books)
				  .twelveMonthBrochures += workingTwelveMonthRecords.Sum(Function(x) x.Brochures)
				  .twelveMonthHours += workingTwelveMonthRecords.Sum(Function(x) x.Hours)
				  .twelveMonthMagazines += workingTwelveMonthRecords.Sum(Function(x) x.Magazines)
				  .twelveMonthReturnVisits += workingTwelveMonthRecords.Sum(Function(x) x.ReturnVisits)
				  .twelveMonthBibleStudies += workingTwelveMonthRecords.Sum(Function(x) x.BibleStudies)
			  End With

			  Return myReportTotals

		  End Function,
		 Sub(reportTotal As ReportTotals)
			 SyncLock (lockObject)
				 With returnReportTotals
					 .Count += reportTotal.Count

					 .threeMonthBooks += reportTotal.threeMonthBooks
					 .threeMonthBrochures += reportTotal.threeMonthBrochures
					 .threeMonthHours += reportTotal.threeMonthHours
					 .threeMonthMagazines += reportTotal.threeMonthMagazines
					 .threeMonthReturnVisits += reportTotal.threeMonthReturnVisits
					 .threeMonthBibleStudies += reportTotal.threeMonthBibleStudies

					 .sixMonthBooks += reportTotal.sixMonthBooks
					 .sixMonthBrochures += reportTotal.sixMonthBrochures
					 .sixMonthHours += reportTotal.sixMonthHours
					 .sixMonthMagazines += reportTotal.sixMonthMagazines
					 .sixMonthReturnVisits += reportTotal.sixMonthReturnVisits
					 .sixMonthBibleStudies += reportTotal.sixMonthBibleStudies

					 .twelveMonthBooks += reportTotal.twelveMonthBooks
					 .twelveMonthBrochures += reportTotal.twelveMonthBrochures
					 .twelveMonthHours += reportTotal.twelveMonthHours
					 .twelveMonthMagazines += reportTotal.twelveMonthMagazines
					 .twelveMonthReturnVisits += reportTotal.twelveMonthReturnVisits
					 .twelveMonthBibleStudies += reportTotal.twelveMonthBibleStudies
				 End With
			 End SyncLock

		 End Sub)

		Return returnReportTotals
	End Function

End Class
